using System;
using System.Diagnostics.Contracts;
using Wx.Sdk.App.Entity;
using Wx.Sdk.Ext;
using Wx.Sdk.Utils;

namespace Wx.Sdk.App.Src;

public class LoginService
{
    private readonly string TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code";
    private readonly string USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}";
    private WxApp wxApp;
    public LoginService(WxApp wxApp)
    {
        this.wxApp = wxApp;
    }
    /// <summary>
    /// 通过 code 获取 access_token
    /// </summary>
    /// <param name="code"></param>
    /// <returns></returns>
    /// <exception cref="WxError"></exception>
    public async Task<AppToken> GetAccessToken(string code)
    {
        var url = string.Format(TOKEN_URL, wxApp.appOption.Appid, wxApp.appOption.Secret, code);
        var str = await this.Get(url);
        var accessToken = JsonHelper.ToModel<AppToken>(str);
        if (accessToken.Errcode != 0) throw new WxError($"{accessToken.Errcode}=>{accessToken.Errmsg}");
        return accessToken ?? throw new WxError("获取access_token失败");
    }
    /// <summary>
    /// 通过 access_token 和 openid 获取用户信息
    /// </summary>
    public async Task<AppUser> GetAppUser(string accessToken, string openId)
    {
        var url = string.Format(USER_INFO_URL, accessToken, openId);
        var str = await this.Get(url);
        return JsonHelper.ToModel<AppUser>(str) ?? throw new WxError("获取用户信息失败");
    }
    /// <summary>
    /// 根据 code 直接获取用户信息
    /// </summary>
    /// <param name="code"></param>
    /// <returns></returns>
    public async Task<AppUser> GetAppUser(string code)
    {
        var token = await this.GetAccessToken(code);
        return await this.GetAppUser(token.Access_Token, token.OpenId);
    }

    /// <summary>
    /// http请求
    /// </summary>
    /// <param name="url"></param>
    /// <returns></returns>
    /// <exception cref="WxError"></exception>
    private async Task<string> Get(string url)
    {
        Contract.Assume(!url.IsNull());
        var client = wxApp.httpClientFactory.CreateClient();
        //远程拉取字符串
        var data = await client.GetStringAsync(url);
        var msg = JsonHelper.ToModel<AppMsg>(data) ?? new AppMsg();
        if (msg.Errcode != 0) throw new WxError($"{msg.Errcode}=>{msg.Errmsg}");
        return data;
    }
}
